package com.redijedi.tapestry.bindings;

import org.apache.tapestry.Binding;
import org.apache.tapestry.ComponentResources;
import org.apache.tapestry.TapestryConstants;
import org.apache.tapestry.internal.bindings.LiteralBinding;
import org.apache.tapestry.ioc.Location;
import org.apache.tapestry.services.BindingFactory;
import org.apache.tapestry.services.BindingSource;

/**
 * This code is taken from the Tapestry Wiki
 * (http://wiki.apache.org/tapestry/Tapestry5HowToAddMessageFormatBindingPrefix)
 * and exists here so that I don't have to implement this in all my projects.
 * All props due to Filip S. Adamsen.
 * <p>
 * The messageformat prefix allows you to specify values to use in a message
 * inline like this:
 * <p>
 * <code>
 * ${messageformat:key,value1,value2} or <t:component
 * t:parameter="messageformat:key,value1,value2">
 * </code>
 * <p>
 * Where the component's message catalog contains:
 * <p>
 * <code>
 * key = This is the first value: %s, it's a string. This is the second value:
 * %d, it's a number.
 * </code>
 * 
 * @author Filip S. Adamsen
 * 
 */
public class MessageFormatBindingFactory implements BindingFactory {

	private final BindingSource bindingSource;

	public MessageFormatBindingFactory(BindingSource bindingSource) {
		this.bindingSource = bindingSource;
	}

	public Binding newBinding(String description, ComponentResources container,
			ComponentResources component, String expression, Location location) {
		String key = expression.substring(0, expression.indexOf(','));
		String[] parts = expression.substring(expression.indexOf(',') + 1)
				.split(",");

		Object[] values = new Object[parts.length];
		for (int i = 0; i < parts.length; i++) {
			String part = parts[i];
			String prefix = TapestryConstants.PROP_BINDING_PREFIX;

			if ('\'' == part.charAt(0)
					&& '\'' == part.charAt(part.length() - 1)) {
				part = part.substring(1, part.length() - 1);
				prefix = TapestryConstants.LITERAL_BINDING_PREFIX;
			}

			values[i] = bindingSource.newBinding(description, container,
					component, prefix, part, location).get();
		}

		String messageValue = container.getMessages().format(key, values);

		return new LiteralBinding(description, messageValue, location) {
			@Override
			public boolean isInvariant() {
				return false;
			}
		};
	}
}